import mimetypes, os
from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponseNotModified, HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.views.static import was_modified_since
from django.utils.http import http_date
from django.views.decorators.cache import never_cache
from django.db import transaction
from models import *
from forms import *


#Utils --------------------------------------------------

def render_to_response(request, template_name, context_dict = {}):
    from django.template import RequestContext
    from django.shortcuts import render_to_response as _render_to_response
    context = RequestContext(request, context_dict)
    return _render_to_response(template_name, context_instance=context)


def render_to(template_name):
    def renderer(func):
        @never_cache
        def wrapper(request, *args, **kw):
            output = func(request, *args, **kw)
            if not isinstance(output, dict):
                return output
            return render_to_response(request, template_name, output)
        return wrapper
    return renderer

def get_user_doc_or_404(request, doc_id):
    try:
        return Document.objects.get(pk=doc_id, owner=request.user)
    except:
        raise Http404()
    

#Views --------------------------------------------------

@login_required
@render_to('documents/list.html')
def list_documents(request, cat_id=None):
    categories = Category.objects.get_user_cats(request.user)
    search_query = request.GET.get('q', '').strip()
    if len(search_query) > 0:
        documents = Document.objects.search(search_query, request.user)
    else:
        documents = Document.objects.filter(owner=request.user)
    if cat_id:
        documents = documents.filter(category__id=cat_id)
    return locals()



@login_required
@render_to('documents/new_document.html')
@transaction.commit_on_success
def new_document(request):
    #TODO in one transaction
    if request.method == 'POST':
        form = NewDocumentForm(request.POST, request.FILES)
        if form.is_valid():
            data = form.cleaned_data
            doc = Document(
                    owner = request.user,
                    category = data['category'],
                    filename = data['filename'],
                    author = data['author'],
                    beneficient = data['beneficient'],
                    issued_on = data['issued_on'],
                    description = data['description'],
                    public = data['public'],
                    access_code = data['access_code']
                    )
            doc.save()
            version = DocumentVersion(document=doc, version=data['version'], file=data['file'])
            version.save_file_file(data['file'].filename, data['file'].content)
            version.save()
            return HttpResponseRedirect(reverse("documents-list"))
    else:
        initial = {'category': request.GET.get('category_id')}
        form = NewDocumentForm(initial=initial)
    return {'form': form}


@login_required
@render_to('documents/document_details.html')
def document_details(request, doc_id):
    return {'document': get_user_doc_or_404(request, doc_id)}


@login_required
@render_to('documents/new_version.html')
@transaction.commit_on_success
def new_version(request, doc_id):
    document = get_user_doc_or_404(request, doc_id)
    if request.method == 'POST':
        form = NewVersionForm(request.POST, request.FILES, document)
        if form.is_valid():
            version = DocumentVersion(
                            document=document,      
                            version=form.cleaned_data['version'], 
                            file=form.cleaned_data['file'])
            version.save_file_file(form.cleaned_data['file'].filename, 
                                   form.cleaned_data['file'].content)
            version.save()
            return HttpResponseRedirect(reverse("documents-details", args=[document.id]))
    else:
        form = NewVersionForm(document=document)
    return {'form':form}


@login_required
@render_to('documents/change_document.html')
def change_document(request, doc_id):
    document = get_user_doc_or_404(request, doc_id)
    if request.method == 'POST':
        form = ChangeDocumentForm(request.POST, instance=document)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse("documents-details", args=[document.id]))
    else:
        initial = {'category': request.GET.get('category_id') or document.category.id}
        form = ChangeDocumentForm(instance=document, initial=initial)
    return {'form':form}

@login_required
def delete_document(request, doc_id):
    document = get_user_doc_or_404(request, doc_id)
    document.delete()
    return HttpResponseRedirect(reverse("documents-list")) 


@login_required
@render_to('documents/new_category.html')
def new_category(request):
    if request.method == 'POST':
        form = CategoryForm(request.POST)
        if form.is_valid():
            category = form.save()
            redirect = request.session.get('cat_redirect') or reverse("documents-list")
            if "?" in redirect:
                redirect = redirect + "&category_id=%d" % category.id
            else:
                redirect = redirect + "?category_id=%d" % category.id
            return HttpResponseRedirect(redirect)
    else:
        request.session["cat_redirect"] = request.META.get('HTTP_REFERER')
        form = CategoryForm()
    return {'form':form}


@render_to('documents/access_code.html')
def serve_document(request, filename, version=None):
    try:
        document = Document.objects.get(filename=filename)
        if version:
            doc_version = document.versions.get(version=version)
        else:
            doc_version = document.versions.order_by('-timestamp')[0]
    except Document.DoesNotExist:
         raise Http404, '"%s" does not exist' % filename
    except DocumentVersion.DoesNotExist:
        raise Http404, 'Version "%s" does not exist for document.' % version
    
    if request.method == 'POST':
        form = AccessDocumentForm(request.POST, document=document)
        if not form.is_valid():
            return {'form':form}
    else:
        if not document.public and document.owner.id != request.user.id:
            if len(document.access_code) == 0:
                return HttpResponseForbidden("403 Forbidden")
            return {'form': AccessDocumentForm()}
        
    
    fullpath = doc_version.get_file_filename()
    
    if not os.path.exists(fullpath):
        raise Http404, '"%s" does not exist' % fullpath

    mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream'
    contents = open(fullpath, 'rb').read()
    response = HttpResponse(contents, mimetype=mimetype)
    response["Content-Length"] = len(contents)
    return response
